/*
 ------------------------------------------------------------------------------
 Copyright (C) 2009-2011 Eternal Games.

 This file is part of the Eternal Tech source code.

 The Eternal Tech source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Eternal Tech source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Eternal Tech source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// r_scene.cpp - Handles scene rendering and lists
//

// TODO:
// - Maybe add scenes similar to crops?
// - Finish commands


#include "r_local.h"


/*
 ==============================================================================

    SCENE LISTS

 ==============================================================================
*/


/*
 ==================
 R_AddEntityToScene
 ==================
*/
void R_AddEntityToScene (const renderEntity_t *renderEntity)
{
	renderEntity_t	*entity;

	if (rg.scene.numEntities >= MAX_RENDER_ENTITIES)
	{
		Com_DevPrintf(S_COLOR_YELLOW "R_AddEntityToScene: MAX_RENDER_ENTITIES hit\n");
		return;
	}

	entity = &rg.scene.entities[rg.scene.numEntities++];

	*entity = *renderEntity;
	entity->index = rg.scene.numEntities - 1;
}

/*
 ==================
 R_AddLightToScene
 ==================
*/
void R_AddLightToScene (const renderLight_t *renderLight)
{
	renderLight_t	*light;

	if (rg.scene.numLights >= MAX_RENDER_LIGHTS)
	{
		Com_DevPrintf(S_COLOR_YELLOW "R_AddLightToScene: MAX_RENDER_LIGHTS hit\n");
		return;
	}

	light = &rg.scene.lights[rg.scene.numLights++];

	*light = *renderLight;
	light->index = rg.scene.numLights - 1;
}

/*
 ==================
 R_AddParticleToScene
 ==================
*/
void R_AddParticleToScene (const renderParticle_t *renderParticle)
{
	renderParticle_t	*particle;

	if (rg.scene.numParticles >= MAX_RENDER_PARTICLES)
	{
		Com_DevPrintf(S_COLOR_YELLOW "R_AddParticleToScene: MAX_RENDER_PARTICLES hit\n");
		return;
	}

	particle = &rg.scene.particles[rg.scene.numParticles++];

	*particle = *renderParticle;
	particle->index = rg.scene.numParticles - 1;
}

/*
 ==================
 R_ClearSceneLists
 ==================
*/
void R_ClearSceneLists ()
{
	rg.scene.numEntities = rg.scene.firstEntity = 1;
	rg.scene.numLights = rg.scene.firstLight = 0;
	rg.scene.numParticles = rg.scene.firstParticle = 0;
}

/*
 ==================
 R_ResetScene
 ==================
*/
void R_ResetScene ()
{
	rg.scene.firstEntity = rg.scene.numEntities;
	rg.scene.firstLight = rg.scene.numLights;
	rg.scene.firstParticle = rg.scene.numParticles;
}


/*
 ==============================================================================

    SCENE RENDERING

 ==============================================================================
*/


/*
 ==================
 R_RenderScene
 ==================
*/
void R_RenderScene (const renderView_t *renderView, bool primaryView)
{
	// If it is a primary view
	if (primaryView)
	{
		if (!rg.worldModel)
			Com_Error(ERR_DROP, "R_RenderScene: NULL worldModel");

		// Copy the primary view
		rg.primaryViewAvailable = true;

		rg.primaryView.renderView = *renderView;

		rg.primaryView.numEntities = rg.scene.numEntities;
		rg.primaryView.firstEntity = rg.scene.firstEntity;

		rg.primaryView.numLights = rg.scene.numLights;
		rg.primaryView.firstLight = rg.scene.firstLight;

		rg.primaryView.numParticles = rg.scene.numParticles;
		rg.primaryView.firstParticle = rg.scene.firstParticle;
	}

	// Copy renderView
	rg.renderView = *renderView;

	// Set up renderViewParms
	rg.renderViewParms.primaryView = primaryView;

	rg.renderViewParms.subview = SUBVIEW_NONE;

	rg.renderViewParms.renderEntities = &rg.scene.entities[rg.scene.firstEntity];
	rg.renderViewParms.numRenderEntities = rg.scene.numEntities - rg.scene.firstEntity;

	rg.renderViewParms.renderLights = &rg.scene.lights[rg.scene.firstLight];
	rg.renderViewParms.numRenderLights = rg.scene.numLights - rg.scene.firstLight;

	rg.renderViewParms.renderParticles = &rg.scene.particles[rg.scene.firstParticle];
	rg.renderViewParms.numRenderParticles = rg.scene.numParticles - rg.scene.firstParticle;

	// Render the main view
	R_RenderView();
}


/*
 ==============================================================================

    CONSOLE COMMANDS

 ==============================================================================
*/


/*
 ==================
 R_ListSceneEntities_f

 FIXME: The "world" should be printed as the world and not as a model
 FIXME2: Sprite and beam materials
 ==================
*/
static void R_ListSceneEntities_f ()
{
	renderEntity_t   *entity;
	int				 i;

	for (i = 0, entity = rg.renderViewParms.renderEntities; i < rg.renderViewParms.numRenderEntities; i++, entity++)
	{
		Com_Printf("%5i: ", entity->index);

		Com_Printf("(%7i, %7i, %7i) ", mathMain::FloatToInt(entity->origin[0]), mathMain::FloatToInt(entity->origin[1]), mathMain::FloatToInt(entity->origin[2]));

		if (entity == rg.worldEntity)
		{
			Com_Printf("WORLD  ");

			if (!rg.primaryViewAvailable || !rg.worldModel)
				Com_Printf("\n");
			else
				Com_Printf("%s\n", rg.worldModel->name);
		}
		else
		{
			switch (entity->reType){
			case RE_MODEL:
				Com_Printf("MODEL  ");

				if (!entity->model || entity->model->type == MODEL_BAD)
					Com_Printf("\n");
				else
					Com_Printf("%s\n", entity->model->name);

				break;
			case RE_SPRITE:
				Com_Printf("SPRITE ");

				//if (entity->material)
				//	Com_Printf("%s\n", entity->material->name);
				//else
					Com_Printf("%s\n", rg.defaultMaterial->name);

				break;
			case RE_BEAM:
				Com_Printf("BEAM   ");

				//if (entity->material)
				//	Com_Printf("%s\n", entity->material->name);
				//else
					Com_Printf("%s\n", rg.defaultMaterial->name);

				break;
			default:
				Com_Printf("?????? ");

				Com_Printf("\n");

				break;
			}
		}
	}

	Com_Printf("--------------------\n");
	Com_Printf("%i active render entities\n", rg.renderViewParms.numRenderEntities);
}

/*
 ==================
 R_ListSceneLights_f

 TODO: Add light type (ambient, point, fog etc...)
 TODO2: Figure out how to also print out static lights because it only prints dynamic ones
 ==================
*/
static void R_ListSceneLights_f ()
{
	renderLight_t   *light;
	int				i;

	for (i = 0, light = rg.renderViewParms.renderLights; i < rg.renderViewParms.numRenderLights; i++, light++)
	{
		Com_Printf("%5i: ", light->index);

		Com_Printf("(%7i, %7i, %7i) ", mathMain::FloatToInt(light->origin[0]), mathMain::FloatToInt(light->origin[1]), mathMain::FloatToInt(light->origin[2]));

		if (light->customMaterial)
			Com_Printf("%s\n", light->customMaterial->name);
		else
			Com_Printf("%s\n", rg.defaultLightMaterial->name);
	}

	Com_Printf("--------------------\n");
	Com_Printf("%i active render lights\n", rg.renderViewParms.numRenderLights);
}

/*
 ==================
 R_ListSceneParticles_f

 TODO: Particle origin and type
 ==================
*/
static void R_ListSceneParticles_f ()
{
	renderParticle_t   *particle;
	int				   i;

	for (i = 0, particle = rg.renderViewParms.renderParticles; i < rg.renderViewParms.numRenderParticles; i++, particle++)
	{
		Com_Printf("%5i: ", particle->index);

		Com_Printf("%s\n", particle->material->name);
	}

	Com_Printf("--------------------\n");
	Com_Printf("%i active render particles\n", rg.renderViewParms.numRenderParticles);
}

static void R_ListSceneDecals_f ()
{
}


/*
 ==============================================================================

    INITIALIZATION AND SHUTDOWN

 ==============================================================================
*/


/*
 ==================
 R_InitScene
 ==================
*/
void R_InitScene ()
{
	// Add commands
	Cmd_AddCommand("listSceneEntities", R_ListSceneEntities_f);
	Cmd_AddCommand("listSceneLights", R_ListSceneLights_f);
	Cmd_AddCommand("listSceneParticles", R_ListSceneParticles_f);
	Cmd_AddCommand("listSceneDecals", R_ListSceneDecals_f);
}

/*
 ==================
 R_ShutdownScene
 ==================
*/
void R_ShutdownScene ()
{
	// Remove commands
	Cmd_RemoveCommand("listSceneEntities");
	Cmd_RemoveCommand("listSceneLights");
	Cmd_RemoveCommand("listSceneParticles");
	Cmd_RemoveCommand("listSceneDecals");
}